package com.cq.hd.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cq.hd.common.enums.biz.*;
import com.cq.hd.common.response.Throw;
import com.cq.hd.common.utils.NoUtils;
import com.cq.hd.common.utils.StringUtils;
import com.cq.hd.member.api.TbAppUserApi;
import com.cq.hd.member.api.TbBusinessMerchantApi;
import com.cq.hd.member.api.vo.AppUserVo;
import com.cq.hd.member.api.vo.BusinessMerchantVo;
import com.cq.hd.order.api.dto.ActiveEnrollInfoSonDto;
import com.cq.hd.order.api.dto.CreateGroupBuyOrderDto;
import com.cq.hd.order.api.dto.CreateOrderDto;
import com.cq.hd.order.api.vo.CreateOrderVo;
import com.cq.hd.order.convert.OrderCreateConvert;
import com.cq.hd.order.mapper.TbOrderItemMapper;
import com.cq.hd.order.mapper.TbOrderMapper;
import com.cq.hd.order.mq.provider.OrderDelayMsgProvider;
import com.cq.hd.order.po.TbGroupBuyOrderPo;
import com.cq.hd.order.po.TbOrderItemPo;
import com.cq.hd.order.po.TbOrderPo;
import com.cq.hd.order.render.OrderContext;
import com.cq.hd.order.render.dto.ActiveGoodsDto;
import com.cq.hd.order.service.OrderCreateService;
import com.cq.hd.order.service.TbGroupBuyOrderService;
import com.cq.hd.product.api.TbActiveApi;
import com.cq.hd.product.api.dto.ActiveGoodsSonDto;
import com.cq.hd.product.api.dto.ActiveSubStockDto;
import com.cq.hd.product.api.vo.ActiveGroupBuyVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author much
 * @since 2024/09/16 12:08
 */
@Slf4j
@Service
public class OrderCreateServiceImpl implements OrderCreateService {

    @Resource
    private TbActiveApi activeApi;
    @Resource
    private TbAppUserApi appUserApi;
    @Resource
    private TbBusinessMerchantApi businessMerchantApi;
    @Resource
    private TbOrderMapper orderMapper;
    @Resource
    private TbOrderItemMapper orderItemMapper;
    @Resource
    private TbGroupBuyOrderService groupBuyOrderService;
    @Resource
    private OrderDelayMsgProvider orderDelayMsgProvider;
    @Resource
    private PlatformTransactionManager transactionManager;

    @Override
    public CreateOrderVo createGroupBuyOrder(OrderContext orderContext) {
        CreateOrderDto createOrderDto = orderContext.getCreateOrderDto();

        TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionAttribute());
        TbOrderPo orderPo = null;
        try {
            // 事务开始
            orderPo = createOrderForGroupBuy(orderContext);
            saveOrderItems(orderContext, orderPo);

            if (createOrderDto.getGroupBuyOrderId() == null) {
                // 开团
                CreateGroupBuyOrderDto createGroupBuyOrderDto = wrapCreateGroupBuyOrderParam(createOrderDto, orderPo);
                groupBuyOrderService.createGroupBuyOrder(createGroupBuyOrderDto);
            } else {
                // 参团
                groupBuyOrderService.joinGroup(createOrderDto.getGroupBuyOrderId(), wrapCreateGroupBuyOrderParam(createOrderDto, orderPo));
            }

            // 扣减活动库存，以及更新红包使用状态和使用时间
            subActiveStockAndRedPackageState(orderContext, orderPo);

            transactionManager.commit(transaction);
        } catch (Exception e) {
            transactionManager.rollback(transaction);
            log.error(e.getMessage(), e);
            Throw.isBusinessException(e.getMessage());
        }

        CreateOrderVo createOrderVo = new CreateOrderVo();
        createOrderVo.setOrderId(orderPo.getId());
        createOrderVo.setOrderNo(orderPo.getOrderNo());
        createOrderVo.setZeroState(orderPo.getZeroState());

        if (!StringUtils.isBlank(createOrderVo.getOrderNo()) && ZeroStateEnum.NO.getValue().equals(createOrderVo.getZeroState())) {
            // 发送延时订单消息
            orderDelayMsgProvider.sendMsg(createOrderVo.getOrderNo());
        }

        return createOrderVo;
    }

    private CreateGroupBuyOrderDto wrapCreateGroupBuyOrderParam(CreateOrderDto createOrderDto, TbOrderPo orderPo) {
        return CreateGroupBuyOrderDto.builder()
                .orderId(orderPo.getId())
                .orderNo(orderPo.getOrderNo())
                .activeId(createOrderDto.getActiveId())
                .groupBuyActiveId(createOrderDto.getGroupBuyActiveId())
                .userId(createOrderDto.getUserId())
                .rewardType(createOrderDto.getRewardType())
                .build();
    }

    private void subActiveStockAndRedPackageState(OrderContext orderContext, TbOrderPo orderPo) {
        ActiveSubStockDto activeSubStockDto = new ActiveSubStockDto();
        activeSubStockDto.setActiveId(orderPo.getActiveId());
        activeSubStockDto.setNum(orderPo.getOrderNum());
        activeSubStockDto.setActiveRedPacketBillPageVo(orderContext.getActiveRedPacketBillPageVo());

        // 需要扣除库存的商品
        List<ActiveGoodsDto> activeGoodsList = orderContext.getActiveGoods();
        List<ActiveGoodsSonDto> activeGoodsSonDtos = activeGoodsList.stream()
                .filter(e -> OrderItemTypeEnum.GOODS.getValue().equals(e.getType())
                        && MulStateEnum.NO.getValue().equals(e.getMulState()))
                .map(e -> BeanUtil.copyProperties(e, ActiveGoodsSonDto.class))
                .collect(Collectors.toList());
        activeSubStockDto.setActiveGoodsSonDtos(activeGoodsSonDtos);
        boolean subResult = activeApi.subActiveStock(activeSubStockDto).unpack();
        if (!subResult) {
            Throw.isBusinessException("活动库存不足");
        }
    }

    private TbOrderPo createOrderForGroupBuy(OrderContext orderContext) {
        TbOrderPo tbOrderPo = OrderCreateConvert.createOrderForGroupBuy(orderContext);

        // 查询商家数据，获取商家自有商户id
        BusinessMerchantVo businessMerchantVo = businessMerchantApi.getOwnByBusinessId(tbOrderPo.getBusinessId(), OwnStateEnum.YES.getValue()).unpack();
        Long merchantId = businessMerchantVo.getMerchantId();
        // 商家自有商户id
        tbOrderPo.setMerchantId(merchantId);

        int insert = orderMapper.insert(tbOrderPo);
        if (insert == 0) {
            Throw.isBusinessException("下单失败");
        }

        return tbOrderPo;
    }

    private List<TbOrderItemPo> saveOrderItems(OrderContext orderContext, TbOrderPo tbOrderPo) {
        CreateOrderDto createOrderDto = orderContext.getCreateOrderDto();
        List<ActiveGoodsDto> activeGoodsList = orderContext.getActiveGoods();

        List<TbOrderItemPo> orderItems = new ArrayList<>();
        Set<String> verifyCodes = new HashSet<>();
        for (int i = 0; i < createOrderDto.getOrderNum(); i++) {
            for (ActiveGoodsDto goodsDto : activeGoodsList) {
                for (int j = 0; j < goodsDto.getGoodsNum(); j++) {
                    TbOrderItemPo orderItem = OrderCreateConvert.createOrderItem(tbOrderPo, goodsDto);
                    orderItem.setItemGroup(i + 1);
                    orderItem.setVerifyCode(generateVerifyCode(verifyCodes));

                    // 报名信息
                    if (OrderItemTypeEnum.SIGN_IN.getValue().equals(orderItem.getItemType())) {
                        List<ActiveEnrollInfoSonDto> activeEnrollInfos = createOrderDto.getActiveEnrollInfos();
                        orderItem.setEnrollInfo(CollectionUtils.isEmpty(activeEnrollInfos) ? "" : JSON.toJSONString(activeEnrollInfos));
                    }

                    orderItemMapper.insert(orderItem);
                    orderItems.add(orderItem);
                }
            }
        }
        return orderItems;
    }

    private String generateVerifyCode(Set<String> verifyCodes) {
        String verifyCode = null;
        while (true) {
            verifyCode = NoUtils.getVerifyCode();
            Integer verifyCodeCount = orderItemMapper.selectCount(new QueryWrapper<TbOrderItemPo>().eq("verify_code", verifyCode));
            if ((verifyCodeCount == null || verifyCodeCount <= 0) && !verifyCodes.contains(verifyCode)) {
                verifyCodes.add(verifyCode);
                break;
            }
        }
        return verifyCode;
    }

}
